<script lang="ts" setup>
import {
  watch,
  onUnmounted,
  onActivated,
  onDeactivated,
  shallowRef,
  useTemplateRef,
  toValue,
  onMounted,
} from 'vue'
import { gsap } from 'gsap'
import type { Props } from './types.ts'

const props = withDefaults(defineProps<Props>(), {
  trigger: 'default',
  start: 'bottom 70%',
  end: 'bottom top',
  maskZIndex: 10,
  bgColor: 'transparent',
})

const gsapCtx = shallowRef<gsap.Context | null>(null)
const gsapTl = shallowRef<gsap.core.Timeline | null>(null)
const maskRef = useTemplateRef<HTMLDivElement | null>('maskRef')
const maskContainerRef = useTemplateRef<HTMLDivElement | null>('maskContainerRef')

const createAnimation = () => {
  if (gsapCtx.value) {
    gsapCtx.value.revert()
  }

  gsapCtx.value = gsap.context(() => {
    const propsTrigger = toValue(props.trigger)
    const trigger = propsTrigger === 'default' ? maskContainerRef.value : propsTrigger

    if (maskRef.value && trigger) {
      gsapTl.value = gsap.timeline()
      gsapTl.value.to(maskRef.value, {
        opacity: 0.7,
        scrollTrigger: {
          trigger,
          scrub: true,
          start: props.start,
          end: props.end,
          invalidateOnRefresh: true,
          ...(props.scrollGroup ?? {}),
        },
      })
    }
  })
}

onMounted(() => {
  createAnimation()
})
onActivated(() => {
  if (gsapTl.value) {
    gsapTl.value.resume()
    return
  }

  createAnimation()
})

watch(
  () => props.trigger,
  () => {
    createAnimation()
  },
)

onDeactivated(() => {
  if (gsapTl.value) {
    gsapTl.value.pause()
  }
})
onUnmounted(() => {
  if (gsapCtx.value) {
    gsapCtx.value.revert()
    gsapCtx.value = null
    gsapTl.value = null
  }
})
</script>

<template>
  <div ref="maskContainerRef" class="mask_container">
    <div class="bottom-bg"></div>
    <div ref="maskRef" class="mask-bg"></div>

    <slot />
  </div>
</template>

<style scoped>
@reference "@/assets/main.css";

.mask_container {
  @apply relative;

  .bottom-bg {
    @apply w-full h-[10%] absolute -z-10 top-[100%];
    background-color: v-bind('bgColor');
  }
  .mask-bg {
    @apply w-full h-[110%] absolute top-0 bg-black opacity-0 pointer-events-none;
    z-index: v-bind('maskZIndex');
  }
}
</style>
